package tech.mhuang.pacebox.core.hit;

import tech.mhuang.pacebox.core.util.CollectionUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.stream.Collectors;

/**
 * 命中工具类
 *
 * @author mhuang
 * @since 1.1.2
 */
public class HitUtil {

    /**
     * 根据命中集合和目标值计算出最符合命中的处理方式
     *
     * @param idList 命中集合
     * @param target 目标值
     * @param <T>    类型
     * @return 最佳集合
     */
    public static <T> List<Hit> process(List<Hit<T>> idList, int target) {
        idList.sort(Comparator.comparing(Hit<T>::getCount).reversed());
        Map<Integer, List<Hit<T>>> limitMap = CollectionUtil.capacity(ConcurrentHashMap.class, target);
        List<Hit<T>> retValList;

        for (int currents = 1; currents <= target; currents++) {
            List<Hit<T>> currentList = limitMap.getOrDefault(currents, new ArrayList<>());
            for (int kind = 0; kind < idList.size(); kind++) {
                int coinVal = idList.get(kind).getCount();
                int oppCoinVal = currents - coinVal;
                if (coinVal <= currents) {
                    int tmpCounts = limitMap.getOrDefault(oppCoinVal, Collections.emptyList()).size() + 1;
                    if (tmpCounts <= currents) {
                        List<Hit<T>> temList = limitMap.getOrDefault(oppCoinVal, new ArrayList<>());
                        List<Hit<T>> copyList = temList.stream().collect(Collectors.toList());
                        //如果已经包含当前面值，则加一
                        if (!copyList.contains(idList.get(kind))) {
                            copyList.add(idList.get(kind));
                        }
                        if (getHitSumValue(copyList) == currents) {
                            currentList = copyList;
                            break;
                        }
                    }
                }
            }
            limitMap.put(currents, currentList);
        }
        retValList = limitMap.getOrDefault(target, new ArrayList<>());
        if (retValList.size() == 0) {
            List<Integer> limitList = limitMap.keySet().stream().filter(x -> limitMap.get(x).size() > 0).collect(Collectors.toList());
            if (limitList.size() > 0) {
                limitList.sort(Comparator.comparingInt(Integer::intValue).reversed());
                Integer max = limitList.get(0);
                retValList = limitMap.get(max);
            }
        }

        return retValList.stream().distinct().collect(Collectors.toList());
    }


    /**
     * 根据命中map的目标（key）和值（value）计算出最符合命中的处理方式
     *
     * @param totalMap 命中map
     * @param target   目标值
     * @return 最佳条件
     */
    public static Map<String, Integer> process(Map<String, Long> totalMap, int target) {
        List<String> totalKey = new ArrayList<>(totalMap.keySet());
        Map<Integer, Map<String, Integer>> limitMap = CollectionUtil.capacity(HashMap.class, target);
        for (int currents = 1; currents <= target; currents++) {
            Map<String, Integer> currentMap = limitMap.getOrDefault(currents, CollectionUtil.capacity(HashMap.class, target));
            for (int kind = 0; kind < totalKey.size(); kind++) {
                int coinVal = totalMap.get(totalKey.get(kind)).intValue();
                int oppCoinVal = currents - coinVal;
                if (limitMap.getOrDefault(target, CollectionUtil.capacity(HashMap.class, target)).size() > 0) {
                    return limitMap.get(target);
                }
                if (coinVal <= currents) {
                    int tmpCounts = getHitSumValue(limitMap.get(oppCoinVal)) + 1;
                    if (tmpCounts <= currents) {
                        Map<String, Integer> temMap = limitMap.getOrDefault(oppCoinVal, CollectionUtil.capacity(HashMap.class, target));
                        Map<String, Integer> cloneMap = new HashMap<>(temMap);
                        if (!cloneMap.containsKey(totalKey.get(kind))) {
                            //如果已经包含当前面值，则加一
                            cloneMap.put(totalKey.get(kind), totalMap.get(totalKey.get(kind)).intValue());
                        }
                        if (getHitSumValue(cloneMap) == currents) {
                            currentMap = cloneMap;
                            break;
                        }
                    }
                }
            }
            limitMap.put(currents, currentMap);
        }
        Integer max = limitMap.keySet().stream().filter(x -> x != null).reduce(Integer::max).get();
        if (max > target) {
            max = target;
        }
        return limitMap.get(max);
    }


    /**
     * 根据命中map的目标一级（key）和值（目标二级、value）计算出最符合命中的处理方式
     *
     * @param paramMap 命中map
     * @param target   目标值
     * @return 最佳条件多个
     */
    public static Set<String> processTwo(Map<String, Map<String, Long>> paramMap, int target) {

        Set<String> returnSet = new ConcurrentSkipListSet<>();
        //先列出关系项
        Set<String> currentList = new ConcurrentSkipListSet<>();
        Set<String> relationCard = new ConcurrentSkipListSet<>();
        Map<String, Integer> valueMap = CollectionUtil.capacity(ConcurrentHashMap.class, paramMap.keySet().size());

        paramMap.forEach((key, value) -> {
            valueMap.put(key, target);
            paramMap.get(key).forEach((nodeKey, nodeValue) -> {
                if (!currentList.add(nodeKey)) {
                    relationCard.add(nodeKey);
                }
            });
        });

        for (String keys : relationCard) {
            boolean canDelete = false;
            for (String area : paramMap.keySet()) {
                Integer value = valueMap.get(area);
                if (paramMap.get(area).containsKey(keys)) {
                    int personCount = paramMap.get(area).get(keys).intValue();
                    if (value - personCount >= 0) {
                        canDelete = true;
                    } else {
                        canDelete = false;
                        break;
                    }
                }
            }
            if (canDelete) {
                for (String area : paramMap.keySet()) {
                    Integer value = valueMap.get(area);
                    if (paramMap.get(area).containsKey(keys)) {
                        int personCount = paramMap.get(area).get(keys).intValue();
                        if (value - personCount >= 0) {
                            valueMap.put(area, (value - personCount));
                            returnSet.add(keys);
                            paramMap.get(area).remove(keys);
                        }
                    }
                }
            }
        }
        for (String area : valueMap.keySet()) {
            int currentTarget = valueMap.get(area);
            int min = paramMap.get(area).values().stream().mapToInt(value -> value.intValue()).min().getAsInt();
            if (currentTarget >= min) {
                Map<String, Integer> map = process(paramMap.get(area), currentTarget);
                if (map != null) {
                    returnSet.addAll(map.keySet());
                }
            }
        }
        return returnSet;
    }

    /**
     * 获取命中了多少值
     *
     * @param <T>    类型
     * @param idList 命中集合
     * @return 结果
     */
    public static <T> int getHitSumValue(List<Hit<T>> idList) {
        if (idList == null || idList.size() == 0) {
            return 0;
        }
        return idList.stream().collect(Collectors.summingInt(Hit<T>::getCount));
    }

    /**
     * 获取命中了多少值
     *
     * @param map 命中map
     * @return 结果
     */
    public static int getHitSumValue(Map<String, Integer> map) {
        if (map == null) {
            return 0;
        }
        return map.values().stream().filter(value -> value != null).mapToInt(value -> value.intValue()).sum();
    }
}
